(function () {
	var dBody = document.body,
		dDoc = document.documentElement,
		ie = navigator.userAgent.indexOf("compatible") > -1 && navigator.userAgent.indexOf("MSIE") > -1;
	ie && (parseFloat(RegExp["$1"]) < 7) && document.execCommand("BackgroundImageCache", false, true);

	function Clip(options){
		this.drag = false;
		this.movestatus = false;
		this.defaults = {
			moveCallBack(){},
			dragBoxClass: 'block',			//裁剪框类名
			initialHeight: 100,				//裁剪框初始高度
			initialWidth: 100,				//裁剪框初始宽度
			minHeight: 100,					//裁剪框最小高度
			minWidth: 100,					//裁剪框最小宽度
			maxWidth: 0,					//裁剪框最大宽度
			maxHeight: 0,					//裁剪框最大高度
			cornerColor: '#39f',			//裁剪框颜色
			encode: 'base64',				//文件类型
			type: 'png',					//保存图片类型
			name: 'img',					//文件名字
			quality: 1						//压缩质量
		};
		this.opt = {...this.defaults, ...options};
		this.style_number = 1;
		this.dragBox = `
			<div class="${options.dragBoxClass}">
				<div action="rightDown" class="rRightDown"></div>
				<div action="leftDown" class="rLeftDown"></div>
				<div action="rightUp" class="rRightUp"></div>
				<div action="leftUp" class="rLeftUp"></div>
				<div action="right" class="rRight"></div>
				<div action="left" class="rLeft"></div>
				<div action="up" class="rUp"></div>
				<div action="down" class="rDown" ></div>
			</div>
		`;
		this.containerHtml = `
			<div id="clipping-container-box">
				<div class="clipping-child clipping-child-bg">
					<div id="clipping-cont"></div>
				</div>
				<div class="clipping-child">
					<p class="ht">预览：<p>
					<div id="clipping-preview"></div>
				</div>
			</div>
			<div class="clipping-confirm-box">
				<div class="clipping-confirm primary" id="clipping-confirm">裁剪</div>
				<div class="clipping-confirm" id="clipping-cancel">取消</div>
			</div>
		`;
		this.css = `#clipping-container>div{width:60%;height:100%;padding:20px;position:fixed;top:0;right:-120%;background:#fff;overflow-y:auto;border-radius:5px 0 0 5px;box-shadow:0 0 10px 4px rgba(0,0,0,.14);transition:all .5s;z-index:999;}#clipping-container .clipping-left{right:0;}#clipping-container.clipping-cover:after{content:'';width:100%;height:100%;position:fixed;top:0;left:0;background:rgba(0,0,0,.4);z-index:99;}#clipping-cont{width:100%;height:100%;margin:0 auto;position:relative;overflow:hidden;background-repeat:no-repeat;background-position:center;background-size:100% 100%;box-shadow:0 0 2000px 2000px rgba(0,0,0,.5);}#clipping-cont .${this.opt.dragBoxClass}{height:100px;width:100px;outline-color:rgba(51,153,255,.75);outline:1px solid ${this.opt.cornerColor};position:absolute;left:0;top:0;box-shadow:0 0 2000px 2000px rgba(0,0,0,.5);cursor:move;z-index:3;}#clipping-container #clipping-container-box{display:flex;list-style-type:none;overflow-y:auto;zoom:1;width:100%;height:calc(100% - 100px);}#clipping-container .clipping-child{flex:1 1 0;opacity:0;margin:10px;height:calc(100% - 20px);}#clipping-container .clipping-child .ht{font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;color:#666;font-size:16px;line-height:2;margin-bottom:10px;}#clipping-container .clipping-child-bg{display:flex;justify-content:center;align-items:center;border:1px solid #ccc;background:url("");overflow:hidden;}.rRightDown,.rLeftDown,.rLeftUp,.rRightUp,.rRight,.rLeft,.rUp,.rDown{position:absolute;background:${this.opt.cornerColor};width:6px;height:6px;z-index:5;font-size:0}.rLeftDown,.rRightUp{cursor:ne-resize}.rRightDown,.rLeftUp{cursor:nw-resize}.rRight,.rLeft{cursor:e-resize}.rUp,.rDown{cursor:n-resize}.rRightDown{bottom:-3px;right:-3px}.rLeftDown{bottom:-3px;left:-3px}.rRightUp{top:-3px;right:-3px}.rLeftUp{top:-3px;left:-3px}.rRight{right:-3px;top:50%}.rLeft{left:-3px;top:50%}.rUp{top:-3px;left:50%}.rDown{bottom:-3px;left:50%}.clipping-confirm-box{display:flex;align-item:center;justify-content:flex-end;margin:20px 0 0;}.clipping-confirm{transition:all .4s;margin-right:15px;width:70px;border-radius:5px;background:#fff; border:1px solid;border-color:#dcdfe6;color:#606266;line-height:34px;font-size:14px;text-align:center;cursor:pointer;}#clipping-preview{border:1px solid #CCC;width:0;height:0;margin:0;background-repeat:no-repeat;background-position:center;}.clipping-confirm:hover{color: #409eff;border-color: #c6e2ff;background-color: #ecf5ff;}.clipping-confirm.primary{background:#409eff;color:#fff;border-color:#409eff;}.clipping-confirm.primary:hover{color: #fff;border-color: #66b1ff;background-color: #66b1ff;}.clipping-confirm-box .clipping-confirm:last-child{margin-right:0;}`;
		this.init();
	}
	Clip.prototype = {
		init(){
			var _this = this,
				div = document.createElement('div');
			if (!this.getElement('#clipping-container')){
				return false;
			}
			this.createHtml();
			this.styleInject();
			this.ele = this.getElement('#clipping-cont');
			this.eleimg = this.getElement('#clipping-preview');
			div.innerHTML = this.dragBox;
			_this.ele.appendChild(div);
			this.constantLeft = document.body.clientWidth * 0.4;
			var new_div = this.getElement('#clipping-container').getElementsByTagName('div')[0];
			this.getElement('#clipping-container').classList.add("clipping-cover");
			new_div.classList.add("clipping-left");
			this.opt.minHeight = this.opt.minHeight < 30 ? 100 : this.opt.minHeight;
			this.opt.minWidth = this.opt.minWidth < 30 ? 100 : this.opt.minWidth;
			this.opt.initialHeight = this.opt.initialHeight < 30 ? 100 : this.opt.initialHeight < this.opt.minHeight ? this.opt.minHeight : this.opt.initialHeight;
			this.opt.initialWidth = this.opt.initialWidth < 30 ? 100 : this.opt.initialWidth < this.opt.minWidth ? this.opt.minWidth : this.opt.initialWidth;
			if(this.opt.clipRadio){
				this.opt.minWidth = this.opt.clipRadio * this.opt.minHeight;
				this.opt.initialWidth = this.opt.clipRadio * this.opt.initialHeight;
				this.getElement('.' + this.opt.dragBoxClass).style.width = this.opt.initialWidth + 'px';
				this.getElement('.' + this.opt.dragBoxClass).style.height = this.opt.initialHeight + 'px';
				this.getElement('.rRight').style.display = 'none';
				this.getElement('.rLeft').style.display = 'none';
				this.getElement('.rUp').style.display = 'none';
				this.getElement('.rDown').style.display = 'none';
			}
			this.confirmBtn = this.getElement('#clipping-confirm');
			this.cancelBtn = this.getElement('#clipping-cancel');
		},
		createHtml(){
			var div = document.createElement('div');
			div.innerHTML = this.containerHtml;
			this.getElement('#clipping-container').appendChild(div);
		},
		styleInject(){
			if (!this.css || typeof document === 'undefined')  return false;
			if(this.style_number == 1){
				var head = document.head || document.getElementsByTagName('head')[0];
				var style = document.createElement('style');
				head.appendChild(style);
				if (style.styleSheet) {
					style.styleSheet.cssText = this.css;
				} else {
					style.appendChild(document.createTextNode(this.css));
				}
			}
			this.style_number++;
		},
		getElement(ele){
			return document.querySelector(ele);
		},
		setImg() {
			var block = this.getElement('.' + this.opt.dragBoxClass);
			var left = block.offsetLeft,
				top = block.offsetTop,
				height = block.clientHeight || block.offsetHeight,
				width = block.clientWidth || block.offsetWidt;
			this.eleimg.style.width = width + 'px';
			this.eleimg.style.height = height + 'px';
			this.eleimg.style.backgroundPosition = "-" + left + "px -" + top + 'px';
		},
		setSize(files){
			var _this = this,
				reader = new FileReader(),
				block = this.getElement('.' + this.opt.dragBoxClass),
				url = window.URL || window.webkitURL,
				img = new Image(),
				child = document.querySelectorAll('.clipping-child'),
				FW = child[0].clientWidth || child[0].offsetWidth,
				FH = child[0].clientHeight || child[0].offsetHeight,
				illegal = false;
			img.src = url.createObjectURL(files);
			img.onload = function () {
				let that = this,
					w = that.width * 1,
					h = that.height * 1;
				if( w > h ){
					_this.ele.style.height = parseInt((FW / w) * h) + 'px';
					_this.eleimg.style.backgroundSize = parseInt(FW) + 'px ' + parseInt((FW / w) * h) + 'px';
				}else if( w < h ){
					_this.ele.style.width = parseInt(( FH / h ) * w) + 'px';
					_this.eleimg.style.backgroundSize = parseInt(( FH / h ) * w) + 'px' + parseInt(FH) + 'px';
				}else{
					let minwh = parseInt(Math.min(FW*1,FH*1));
					_this.ele.style.height = minwh + 'px';
					_this.ele.style.width = minwh + 'px';
					_this.eleimg.style.backgroundSize = minwh + 'px ' + minwh + 'px';
				}
				_this.imgOrginWidth = w;
				_this.imgOrginHeight = h;
				_this.opt.maxWidth = parseInt(_this.opt.maxWidth > w ? w : _this.opt.maxWidth);
				_this.opt.maxHeight = parseInt(_this.opt.maxHeight > h ? h : _this.opt.maxHeight);
				if(!(_this.opt.maxWidth && _this.opt.maxWidth >= 30) && _this.opt.maxHeight && _this.opt.maxHeight >= 30){
					if(_this.opt.clipRadio){
						_this.opt.maxWidth = parseInt(_this.opt.maxHeight * _this.opt.clipRadio);
					}else{
						_this.opt.maxWidth = parseInt(_this.ele.offsetWidth);
					}
				}else if(!(_this.opt.maxHeight && _this.opt.maxHeight >= 30) && _this.opt.maxWidth && _this.opt.maxWidth >= 30){
					if(_this.opt.clipRadio){
						_this.opt.maxHeight = parseInt(_this.opt.maxWidth / _this.opt.clipRadio);
					}else{
						_this.opt.maxHeight = parseInt(_this.ele.offsetHeight);
					}
				}else if(!(_this.opt.maxWidth && _this.opt.maxWidth >= 30) && !(_this.opt.maxHeight && _this.opt.maxHeight >= 30)){
					if(_this.opt.clipRadio){
						if(_this.ele.offsetHeight * _this.opt.clipRadio > _this.ele.offsetWidth){
							_this.opt.maxWidth = parseInt(_this.ele.offsetWidth);
							_this.opt.maxHeight = parseInt(_this.opt.maxWidth / _this.opt.clipRadio);
						}else{
							_this.opt.maxWidth = parseInt(_this.ele.offsetHeight * _this.opt.clipRadio);
						}
					}else{
						_this.opt.maxWidth = parseInt(_this.ele.offsetWidth);
						_this.opt.maxHeight = parseInt(_this.ele.offsetHeight);
					}
				}else{
					if(_this.opt.clipRadio){
						if(_this.opt.maxHeight * _this.opt.clipRadio > _this.ele.offsetWidth){
							_this.opt.maxWidth = parseInt(_this.ele.offsetWidth);
							_this.opt.maxHeight = parseInt(_this.opt.maxWidth / _this.opt.clipRadio);
						}else{
							_this.opt.maxWidth = parseInt(_this.opt.maxHeight * _this.opt.clipRadio);
						}
					}else{
						_this.opt.maxWidth = parseInt(_this.ele.offsetWidth);
						_this.opt.maxHeight = parseInt(_this.ele.offsetHeight);
					}
				}
				if(_this.opt.initialHeight > _this.opt.maxHeight){
					illegal = true;
					if(_this.opt.clipRadio){
						_this.opt.initialWidth = parseInt(_this.opt.maxHeight * _this.opt.clipRadio);
					}
					_this.opt.initialHeight = parseInt(_this.opt.maxHeight);
				}
				if(_this.opt.initialWidth > _this.opt.maxWidth){
					illegal = true;
					if(_this.opt.clipRadio){
						_this.opt.initialHeight = parseInt(_this.opt.maxWidth / _this.opt.clipRadio);
					}
					_this.opt.initialWidth = parseInt(_this.opt.maxWidth);
				}
				if(illegal){
					_this.getElement('.' + _this.opt.dragBoxClass).style.width = _this.opt.initialWidth + 'px';
					_this.getElement('.' + _this.opt.dragBoxClass).style.height = _this.opt.initialHeight + 'px';
					_this.eleimg.style.width = _this.opt.initialWidth + 'px';
					_this.eleimg.style.height = _this.opt.initialHeight + 'px';
				}
			};
			reader.readAsDataURL(files);
			reader.onload = e => {
				_this.ele.style.backgroundImage = "url('" + e.target.result + "')";
				_this.eleimg.style.backgroundImage = "url('" + e.target.result + "')";
			};
            child[0].style.opacity = 1;
            child[1].style.opacity = 1;

			_this.opt.width = _this.opt.initialWidth;
			_this.opt.height = _this.opt.initialHeight;
			_this.opt.top = 0;
			_this.opt.left = 0;

			block.addEventListener("mousedown", function(e){
				e.clientX = e.clientX + _this.constantLeft;
				_this.start(e);
			});
			document.addEventListener("mousemove", function(e) {
				e.clientX = e.clientX + _this.constantLeft;
				_this.move(e, _this.movestatus);
			});
			document.addEventListener("mouseup", function(){
				_this.drag = false;
				ie && _this.getElement('.' + _this.opt.dragBoxClass).releaseCapture();
			});
			_this.img = img;
			_this.setImg();
			_this.confirmBtn.addEventListener('click', _this.finished.bind(_this));
			_this.cancelBtn.addEventListener('click', _this.cancel.bind(_this));
		},
		start(e) {
			var _this = this,
				block = this.getElement('.' + this.opt.dragBoxClass),
				container = this.ele,
				$elem = e.target,
				action = $elem.getAttribute("action");
			this.offset = {
				height: container.offsetHeight,
				width: container.offsetWidth,
				left: container.offsetLeft + this.constantLeft,
				top: container.offsetTop,
			};
			this.blockOriginal = {
				height: block.offsetHeight,
				width: block.offsetWidth,
				left: parseInt(block.offsetLeft),
				top: parseInt(block.offsetTop)
			};
			if (action) {
				this.fun = this[action];
				_this.movestatus = false;
			} else {
				this.x = e.clientX - this.offset.left - this.blockOriginal.left;
				this.y = e.clientY - this.offset.top - this.blockOriginal.top;
				_this.movestatus = true;
			}
			_this.drag = true;
		},
		move(e, isMove) {
			if(!this.drag) return false;
			window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
			var block = this.getElement('.' + this.opt.dragBoxClass),
				radio = this.opt.clipRadio;
			if (isMove) {
				var left = Math.max(0, e.clientX - this.offset.left - this.x);
				left = Math.min(left, this.offset.width - this.blockOriginal.width);
				var top = Math.max(0, e.clientY - this.offset.top - this.y);
				top = Math.min(top, this.offset.height - this.blockOriginal.height);
				block.style.left = left + 'px';
				block.style.top = top + 'px';
				this.opt.left = left;
				this.opt.top = top;
			} else {
				var offset = this.fun(e),
					w = typeof(offset.width) == "undefined" ? this.blockOriginal.width : offset.width,
					h = typeof(offset.height) == "undefined" ? this.blockOriginal.height : offset.height,
					t = typeof(offset.top) == "undefined" ? this.blockOriginal.top : offset.top,
					l = typeof(offset.left) == "undefined" ? this.blockOriginal.left : offset.left;
				if(radio){
					w = h * radio;
				}
				if(w <= this.opt.minWidth){
					w = this.opt.minWidth;
				}else if(w >= this.opt.maxWidth){
					w = this.opt.maxWidth;
				}else{
					if(w + l > this.ele.offsetWidth){
						l = l - (w + l - this.ele.offsetWidth);
					}
					block.style.left = l + 'px';
					this.opt.left = l;
				}

				if(h <= this.opt.minHeight){
					h = this.opt.minHeight;
				}else if(h >= this.opt.maxHeight){
					h = this.opt.maxHeight;
				}else{
					if(h + t > this.ele.offsetHeight){
						t = t - (h + t - this.ele.offsetHeight);
					}
					block.style.top = t + 'px';
					this.opt.top = t;
				}
				block.style.width = w + 'px';
				block.style.height = h + 'px';
				this.opt.width = w;
				this.opt.height = h;
			}
			this.setImg();
			this.opt.moveCallBack();
		},
		down(e) {
			var blockOriginal = this.blockOriginal,
				sTop = Math.max(dBody.scrollTop, dDoc.scrollTop),
				offset = this.offset;
			if (e.clientY - offset.top >= blockOriginal.top - sTop) {
				var height = Math.min(offset.height - blockOriginal.top, e.clientY - offset.top - blockOriginal.top + sTop),
					top = blockOriginal.top;
			} else {
				var height = Math.min(offset.top + blockOriginal.top - e.clientY - sTop, blockOriginal.top),
					top = Math.max(e.clientY - offset.top + sTop, 0);
			}
			return {
				height: height,
				top: top
			};
		},
		up(e) {
			var blockOriginal = this.blockOriginal,
				sTop = Math.max(dBody.scrollTop, dDoc.scrollTop),
				offset = this.offset;
			if (e.clientY - offset.top - blockOriginal.height <= blockOriginal.top - sTop) {
				var top = Math.max(e.clientY - offset.top + sTop, 0),
					maxHeight = blockOriginal.top + blockOriginal.height,
					height = Math.min(maxHeight, blockOriginal.top + blockOriginal.height - (e.clientY - offset.top) - sTop);
			} else {
				var height = Math.min(e.clientY - offset.top - blockOriginal.top - blockOriginal.height + sTop, offset.height - blockOriginal.top - blockOriginal.height),
					top = blockOriginal.top + blockOriginal.height;
			}
			return {
				height: height,
				top: top
			};
		},
		left(e) {
			var blockOriginal = this.blockOriginal,
				offset = this.offset;
			if (e.clientX - offset.left - blockOriginal.width - blockOriginal.left <= 0) {
				var left = Math.max(e.clientX - offset.left, 0),
					width = Math.min(blockOriginal.left + blockOriginal.width, blockOriginal.left + blockOriginal.width - (e.clientX - offset.left));
			} else {
				var width = Math.min(e.clientX - offset.left - blockOriginal.left - blockOriginal.width, offset.width - blockOriginal.left - blockOriginal.width),
					left = blockOriginal.left + blockOriginal.width;
			}
			return {
				left: left,
				width: width
			};
		},
		right(e) {
			var blockOriginal = this.blockOriginal,
				offset = this.offset;
			if (e.clientX - offset.left >= blockOriginal.left) {
				var width = Math.min(offset.width - blockOriginal.left, e.clientX - offset.left - blockOriginal.left),
					left = blockOriginal.left;
			} else {
				var width = Math.min(offset.left + blockOriginal.left - e.clientX, blockOriginal.left),
					left = Math.max(e.clientX - offset.left, 0);
			}
			return {
				left: left,
				width: width
			};
		},
		rightDown(e) {
			return {...this.right(e), ...this.down(e)};
		},
		leftDown(e) {
			return {...this.left(e), ...this.down(e)};
		},
		rightUp(e) {
			return {...this.right(e), ...this.up(e)};
		},
		leftUp(e) {
			return {...this.left(e), ...this.up(e)};
		},
		cancel(){
			let container = this.getElement('#clipping-container');
			container.removeChild(container.childNodes[0]);
			this.img = null;
			this.getElement('#clipping-container').classList.remove("clipping-cover");
			this.cancelBtn.onclick = false;
			this.confirmBtn.onclick = false;
		},
		finished(){
			var _this = this,
				img = { width: _this.opt.width, height: _this.opt.height, top: _this.opt.top, left: _this.opt.left, o_width: _this.imgOrginWidth, o_height: _this.imgOrginHeight},
				zoomRadio = img.o_width / _this.ele.offsetWidth;
			img.width = (img.width * zoomRadio).toFixed(2) * 1;
			img.height = (img.height * zoomRadio).toFixed(2) * 1;
			img.top = (img.top * zoomRadio).toFixed(2) * 1;
			img.left = (img.left * zoomRadio).toFixed(2) * 1;
			var canvas = document.createElement('canvas'),
				dw = img.width,
				dh = img.height;
			canvas.width = img.width;
			canvas.height = img.height;
			var ctx = canvas.getContext('2d');
			ctx.fillStyle = '#fff';
			ctx.fillRect(0, 0, canvas.width, canvas.height);
			if(_this.opt.quality != 1){
				dw = img.width * _this.opt.quality;
				dh = img.height * _this.opt.quality;
			}
			ctx.drawImage(this.img, img.left, img.top, img.width, img.height, 0, 0, dw, dh);
			if (this.opt.onDone) {
				let container = this.getElement('#clipping-container');
				container.removeChild(container.childNodes[0]);
				_this.img = null;
				_this.getElement('#clipping-container').classList.remove("clipping-cover");
				switch (this.opt.encode) {
					case 'base64':
						this.opt.onDone(canvas.toDataURL('image/' + this.opt.type, this.opt.quality));
						break;
					case 'blob':
						canvas.toBlob(function (blob) {
							_this.opt.onDone(blob);
						}, 'image/' + this.opt.type);
						break;
					case 'file':
						canvas.toBlob(function (blob) {
							var file = new window.File([blob], _this.opt.name, {
								type: 'image/' + _this.opt.type
							});
							_this.opt.onDone(file);
						}, 'image/' + this.opt.type);
						break;
					default:
						this.opt.onDone(canvas.toDataURL('image/' + this.opt.type, this.opt.quality));
						break;
				};
			}
		}
	};
	window.Clip = Clip;
})();